Add patch for Python 3.13 opcodes
authorStuart Prescott <stuart@debian.org>
Thu, 9 Jan 2025 13:30:25 +0000 (00:30 +1100)
committerStuart Prescott <stuart@debian.org>
Thu, 9 Jan 2025 13:30:25 +0000 (00:30 +1100)
Cherry-pick of ad18260e583a30505e42b04fd242c52ff36f735c

Closes: #1092529
debian/patches/0011-Upstream-patch-for-3.13-opcodes.patch [new file with mode: 0644]
debian/patches/series

diff --git a/debian/patches/0011-Upstream-patch-for-3.13-opcodes.patch b/debian/patches/0011-Upstream-patch-for-3.13-opcodes.patch
new file mode 100644 (file)
index 0000000..29d19fb
--- /dev/null
@@ -0,0 +1,189 @@
+From: Stuart Prescott <stuart@debian.org>
+Date: Fri, 10 Jan 2025 00:14:14 +1100
+Subject: Upstream patch for 3.13 opcodes
+
+Cherry-pick ad18260e583a30505e42b04fd242c52ff36f735c from upstream
+---
+ sources/pyside6/tests/pysidetest/enum_test.py     | 41 ++++++++++++++++-------
+ sources/shiboken6/libshiboken/sbkfeature_base.cpp | 21 +++++++++---
+ sources/shiboken6/libshiboken/sbkmodule.cpp       |  9 +++--
+ 3 files changed, 52 insertions(+), 19 deletions(-)
+
+diff --git a/sources/pyside6/tests/pysidetest/enum_test.py b/sources/pyside6/tests/pysidetest/enum_test.py
+index 8328345..7afc5b9 100644
+--- a/sources/pyside6/tests/pysidetest/enum_test.py
++++ b/sources/pyside6/tests/pysidetest/enum_test.py
+@@ -1,4 +1,4 @@
+-# Copyright (C) 2022 The Qt Company Ltd.
++# Copyright (C) 2024 The Qt Company Ltd.
+ # SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+ import os
+@@ -50,6 +50,8 @@ class ListConnectionTest(unittest.TestCase):
+ # PYSIDE-1735: We are testing that opcodes do what they are supposed to do.
+ #              This is needed in the PyEnum forgiveness mode where we need
+ #              to introspect the code if an Enum was called with no args.
++
++# flake8: noqa
+ class InvestigateOpcodesTest(unittest.TestCase):
+     def probe_function1(self):
+@@ -162,25 +164,40 @@ class InvestigateOpcodesTest(unittest.TestCase):
+             self.assertEqual(self.read_code(self.probe_function2, adaptive=True), result_3)
+             self.assertEqual(self.get_sizes(self.probe_function2, adaptive=True), sizes_3)
+-        if sys.version_info[:2] >= (3, 12):
++        if sys.version_info[:2] == (3, 12):
+-            result_1 = [('RESUME', 151, 0),
+-                        ('LOAD_GLOBAL', 116, 0),
+-                        ('LOAD_ATTR', 106, 2),
+-                        ('STORE_FAST', 125, 1),
++            result_1 = [('RESUME',       151, 0),
++                        ('LOAD_GLOBAL',  116, 0),
++                        ('LOAD_ATTR',    106, 2),
++                        ('STORE_FAST',   125, 1),
+                         ('RETURN_CONST', 121, 0)]
+-            result_2 = [('RESUME', 151, 0),
+-                        ('LOAD_GLOBAL', 116, 1),
+-                        ('LOAD_ATTR', 106, 2),
+-                        ('CALL', 171, 0),
+-                        ('STORE_FAST', 125, 1),
++            result_2 = [('RESUME',       151, 0),
++                        ('LOAD_GLOBAL',  116, 1),
++                        ('LOAD_ATTR',    106, 2),
++                        ('CALL',         171, 0),
++                        ('STORE_FAST',   125, 1),
+                         ('RETURN_CONST', 121, 0)]
++        if sys.version_info[:2] >= (3, 13):
++
++            result_1 = [('RESUME',       149, 0),
++                        ('LOAD_GLOBAL',   91, 0),
++                        ('LOAD_ATTR',     82, 2),
++                        ('STORE_FAST',   110, 1),
++                        ('RETURN_CONST', 103, 0)]
++
++            result_2 = [('RESUME',       149, 0),
++                        ('LOAD_GLOBAL',   91, 0),
++                        ('LOAD_ATTR',     82, 2),
++                        ('PUSH_NULL',     34, None),
++                        ('CALL',          53, 0),
++                        ('STORE_FAST',   110, 1),
++                        ('RETURN_CONST', 103, 0)]
++
+         self.assertEqual(self.read_code(self.probe_function1), result_1)
+         self.assertEqual(self.read_code(self.probe_function2), result_2)
+ if __name__ == '__main__':
+     unittest.main()
+-
+diff --git a/sources/shiboken6/libshiboken/sbkfeature_base.cpp b/sources/shiboken6/libshiboken/sbkfeature_base.cpp
+index fe6f579..07f3ff7 100644
+--- a/sources/shiboken6/libshiboken/sbkfeature_base.cpp
++++ b/sources/shiboken6/libshiboken/sbkfeature_base.cpp
+@@ -92,8 +92,12 @@ void disassembleFrame(const char *marker)
+     PyErr_Restore(error_type, error_value, error_traceback);
+ }
+-// python 3.12
+-static int const CALL = 171;
++// Python 3.13
++static int const LOAD_ATTR_313 = 82;
++static int const CALL_313 = 53;
++static int const PUSH_NULL_313 = 34;
++// Python 3.12
++static int const CALL_312 = 171;
+ // Python 3.11
+ static int const PRECALL = 166;
+ // we have "big instructions" with gaps after them
+@@ -105,13 +109,16 @@ static int const LOAD_METHOD = 160;
+ static int const CALL_METHOD = 161;
+ // Python 3.6
+ static int const CALL_FUNCTION = 131;
+-static int const LOAD_ATTR = 106;
++static int const LOAD_ATTR_312 = 106;
+ // NoGil (how long will this exist in this form?)
+ static int const LOAD_METHOD_NOGIL = 55;
+ static int const CALL_METHOD_NOGIL = 72;
+ static bool currentOpcode_Is_CallMethNoArgs()
+ {
++    static auto number = _PepRuntimeVersion();
++    static int LOAD_ATTR = number < 0x030D00 ? LOAD_ATTR_312 : LOAD_ATTR_313;
++    static int CALL = number < 0x030D00 ? CALL_312 : CALL_313;
+     // PYSIDE-2221: Special case for the NoGil version:
+     //              Find out if we have such a version.
+     //              We could also ask the variable `Py_NOGIL`.
+@@ -150,7 +157,6 @@ static bool currentOpcode_Is_CallMethNoArgs()
+     }
+     uint8_t opcode2 = co_code[f_lasti + 2];
+     uint8_t oparg2 = co_code[f_lasti + 3];
+-    static auto number = _PepRuntimeVersion();
+     if (number < 0x030B00)
+         return opcode1 == LOAD_METHOD && opcode2 == CALL_METHOD && oparg2 == 0;
+@@ -160,7 +166,7 @@ static bool currentOpcode_Is_CallMethNoArgs()
+         //       don't need to take care of them.
+         if (opcode1 == LOAD_METHOD)
+             f_lasti += LOAD_METHOD_GAP_311;
+-        else if (opcode1 == LOAD_ATTR)
++        else if (opcode1 == LOAD_ATTR_312)
+             f_lasti += LOAD_ATTR_GAP_311;
+         else
+             return false;
+@@ -178,6 +184,11 @@ static bool currentOpcode_Is_CallMethNoArgs()
+     else
+         return false;
++    if (number >= 0x030D00) {
++        int opcode3 = co_code[f_lasti + 2];
++        if (opcode3 == PUSH_NULL_313)
++            f_lasti += 2;
++    }
+     opcode2 = co_code[f_lasti + 2];
+     oparg2 = co_code[f_lasti + 3];
+diff --git a/sources/shiboken6/libshiboken/sbkmodule.cpp b/sources/shiboken6/libshiboken/sbkmodule.cpp
+index adcd675..7891fde 100644
+--- a/sources/shiboken6/libshiboken/sbkmodule.cpp
++++ b/sources/shiboken6/libshiboken/sbkmodule.cpp
+@@ -209,6 +209,9 @@ static PyMethodDef module_methods[] = {
+ // Python 3.8 - 3.12
+ static int const LOAD_CONST_312 = 100;
+ static int const IMPORT_NAME_312 = 108;
++// Python 3.13
++static int const LOAD_CONST_313 = 83;
++static int const IMPORT_NAME_313 = 75;
+ static bool isImportStar(PyObject *module)
+ {
+@@ -221,6 +224,9 @@ static bool isImportStar(PyObject *module)
+     static PyObject *const _co_consts = Shiboken::String::createStaticString("co_consts");
+     static PyObject *const _co_names = Shiboken::String::createStaticString("co_names");
++    static int LOAD_CONST = _PepRuntimeVersion() < 0x030D00 ? LOAD_CONST_312 : LOAD_CONST_313;
++    static int IMPORT_NAME = _PepRuntimeVersion() < 0x030D00 ? IMPORT_NAME_312 : IMPORT_NAME_313;
++
+     auto *obFrame = reinterpret_cast<PyObject *>(PyEval_GetFrame());
+     if (obFrame == nullptr)
+         return true;            // better assume worst-case.
+@@ -240,7 +246,7 @@ static bool isImportStar(PyObject *module)
+         PyBytes_AsStringAndSize(dec_co_code, &co_code, &code_len);
+         uint8_t opcode2 = co_code[f_lasti];
+         uint8_t opcode1 = co_code[f_lasti - 2];
+-        if (opcode1 == LOAD_CONST_312 && opcode2 == IMPORT_NAME_312) {
++        if (opcode1 == LOAD_CONST && opcode2 == IMPORT_NAME) {
+             uint8_t oparg1 = co_code[f_lasti - 1];
+             uint8_t oparg2 = co_code[f_lasti + 1];
+             AutoDecRef dec_co_consts(PyObject_GetAttr(dec_f_code, _co_consts));
+@@ -458,7 +464,6 @@ PyObject *create(const char * /* modName */, void *moduleData)
+         Py_INCREF(origImportFunc);
+         AutoDecRef func(PyCFunction_NewEx(lazy_methods, nullptr, nullptr));
+         PyDict_SetItemString(builtins, "__import__", func);
+-        // Everything is set.
+         lazy_init = true;
+     }
+     // PYSIDE-2404: Nuitka inserts some additional code in standalone mode
index 6e6f6bb2cde1f50e5c3f2518576931a89ad6c6a6..0bb921d8d67ef0dcf28881b29d8e43c634b33406 100644 (file)
@@ -8,3 +8,4 @@
 0008-XFAIL-smart-smart_pointer.patch
 0009-XFAIL-QtQml-qquickitem_grabToImage.patch
 0010-Add-Python-3.13-as-supported-version.patch
+0011-Upstream-patch-for-3.13-opcodes.patch